#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h> /* pause() */

#include <xcb/xcb.h>

int main()
{
    /* Open the connection to the X server */
    xcb_connection_t *connection = xcb_connect(NULL, NULL);

    /* Get the first screen */
    const xcb_setup_t *setup = xcb_get_setup(connection);
    xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
    xcb_screen_t *screen = iter.data;

    xcb_window_t window = screen->root;
    xcb_gcontext_t foreground = xcb_generate_id(connection);

    xcb_generic_event_t *pEvent;
    uint32_t mask = XCB_GC_FOREGROUND || XCB_GC_GRAPHICS_EXPOSURES;
    uint32_t values[2] = {screen->black_pixel, 0};
    // create black (foreground) graphic context
    xcb_create_gc(connection, foreground, window, mask, values);

    // create white (background) graphic context
    xcb_gcontext_t background = xcb_generate_id(connection);
    mask = XCB_GC_BACKGROUND || XCB_GC_GRAPHICS_EXPOSURES;
    values[0] = screen->white_pixel;
    values[1] = 0;
    xcb_create_gc(connection, background, window, mask, values);

    /* Create the window */
    window = xcb_generate_id(connection);
    mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
    values[0] = screen->white_pixel;
    values[1] = XCB_EVENT_MASK_EXPOSURE;

    xcb_create_window(connection,                    /* Connection          */
                      XCB_COPY_FROM_PARENT,          /* depth (same as root)*/
                      window,                        /* window Id           */
                      screen->root,                  /* parent window       */
                      20, 20,                        /* x, y                */
                      640, 480,                      /* width, height       */
                      10,                            /* border_width        */
                      XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class               */
                      screen->root_visual,           /* visual              */
                      mask,                          /* masks               */
                      values);

    const char *title = "Hello, Engine!";
    const char *title_icon = "Hello, Engine! (iconified)";

    xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window,
                        XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
                        strlen(title), title);

    xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window,
                        XCB_ATOM_WM_ICON_NAME, XCB_ATOM_STRING, 8,
                        strlen(title_icon), title_icon);

    /* Map the window on the screen */
    xcb_map_window(connection, window);

    /* Make sure commands are sent before we pause so that the window gets shown */
    xcb_flush(connection);

    uint8_t isQuit = 0;
    while ((pEvent = xcb_wait_for_event(connection)) && !isQuit)
    {
        switch (pEvent->response_type & ~0x80)
        {
        case XCB_EXPOSE:
            printf("XCB_EXPOSE break ...........\n");
            xcb_rectangle_t rect = { 20, 20, 60, 80 };
            xcb_poly_fill_rectangle(connection, window, foreground, 1, &rect);
            xcb_flush(connection);
            break;
        case XCB_KEY_PRESS:
            isQuit = 1;
            printf("XCB_EXPOSE XCB_KEY_PRESS ...........\n");
            break;
        }
        free(pEvent);
    }

    xcb_disconnect(connection);
    printf("end ...........");
    return 0;
}